package com.meng.demo1.consistenthash;

import com.sun.javafx.scene.control.skin.VirtualFlow;

import java.awt.*;
import java.util.*;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description:
 *
 * @Author: menglinggang
 * @Date: 2020-07-07
 * @Time: 下午2:38
 */
public class ConsistentHashingRouter implements Router {

    private SortedMap<Long, RouterNode> routerNodeMap = new TreeMap<Long, RouterNode>();

    private List<RouterNode> routerNodeList = new ArrayList<RouterNode>();

    private IHashAlgorithm hashAlgorithm = new HashAlgorithm();

    @Override
    public boolean addServer(String serverId) {
        RouterNode node = createRouterNode(serverId);
        routerNodeList.add(node);
        for (int index = 0 ; index < 50; index++) {
            for (Long nodePosition : nodePositions(node.getServerId(), index)) {
                routerNodeMap.put(nodePosition, node);
            }
        }

        return true;
    }

    @Override
    public boolean removeServer(String serverId) {
        for (RouterNode node : routerNodeList) {
            if (node.getServerId().equals(serverId)) {
                node.setDisable(true);
            }
        }
        return true;
    }

    @Override
    public String routeServer(String key) {
        RouterNode node = null;

        // 获取key的散列值
        Long serverHashCode = hashAlgorithm.hash(key);
        if (routerNodeMap.containsKey(serverHashCode)) {
            node = routerNodeMap.get(serverHashCode);
            if (node != null && !node.isDisable()) {
                return node.getServerId();
            }
        }

        SortedMap<Long, RouterNode> targetServerMap =  routerNodeMap.tailMap(serverHashCode);


        if (targetServerMap != null && !targetServerMap.isEmpty()) {
            node = getEnableServerNode(targetServerMap);
        }

        if (node == null) {
            node = getEnableServerNode(routerNodeMap);
        }

        return node == null ? null : node.getServerId();
    }

    private List<Long> getHashCodes(String key) {

        byte[] digest = HashAlgorithm.computeMd5(key);
        List<Long> codes = new ArrayList<Long>();
        Long hashCode = null;
        for(int h=0 ; h<4; h++) {
            hashCode = ((long) (digest[3 + h * 4] & 0xFF) << 24)
                    | ((long) (digest[2 + h * 4] & 0xFF) << 16)
                    | ((long) (digest[1 + h * 4] & 0xFF) << 8)
                    | (digest[h * 4] & 0xFF);
            codes.add(hashCode);
        }
        return codes ;
    }

    private RouterNode getEnableServerNode(SortedMap<Long, RouterNode> targetServerMap) {
        if (targetServerMap == null || targetServerMap.isEmpty()){
            return null;
        }

        SortedMap<Long, RouterNode> routerNodes = new TreeMap<Long, RouterNode>();
        for (Map.Entry<Long, RouterNode> entry : targetServerMap.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().isDisable()) {
                routerNodes.put(entry.getKey(), entry.getValue());
            }
        }

        if (routerNodes.isEmpty()) {
            return null;
        }

        return routerNodes.get(routerNodes.firstKey()) ;
    }

    private RouterNode createRouterNode(String serverId){
        RouterNode node = new RouterNode();
        node.setServerId(serverId);
        node.setServerName(serverId);
        node.setDisable(false);
        return node;
    }

    private List<Long> nodePositions(String serverId, Integer index){
        return getHashCodes(serverId + "_" + index);

    }


    public static void main(String[] args) {
        Router router = new ConsistentHashingRouter();

        Map<String, Integer> keyMap = new HashMap<String, Integer>();
        keyMap.put("192.168.10.1", 0);
        keyMap.put("192.168.10.2", 0);
        keyMap.put("192.168.10.3", 0);
        keyMap.put("192.168.80.89", 0);
        keyMap.put("192.168.101.13", 0);
        keyMap.put("192.168.101.12", 0);
        keyMap.put("192.168.101.33", 0);
        keyMap.put("192.168.121.13", 0);
        keyMap.put("192.168.121.12", 0);
        keyMap.put("192.168.121.33", 0);

        for (String key: keyMap.keySet()) {
            router.addServer(key);
        }

        for (int i = 0 ; i < 1000000 ; i++) {
            String key = router.routeServer("rxhejdshjduser:id:"+i );
            Integer value = keyMap.get(key);
            value = value + 1;
            keyMap.put(key,value);
        }

        for (Map.Entry<String, Integer> entry : keyMap.entrySet()) {
            System.out.println(entry.getKey() + "----" + entry.getValue());
        }
        double[] vas = new double[keyMap.values().size()];
        int i = 0;
        for (double item : keyMap.values()) {
            vas[i] = item;
            i ++;
        }
        System.out.println("standardDeviation:" + standardDeviation(vas));

        System.out.println("deviation:" + deviation(vas));

    }

    public static int standardDeviation(double[] x) {
        return (int)Math.sqrt(deviation(x));
    }

    public static int deviation(double[] x) {
        int m=x.length;
        double sum=0;
        for(int i=0;i<m;i++){//求和
            sum+=x[i];
        }
        double dAve=sum/m;//求平均值
        double dVar=0;
        for(int i=0;i<m;i++){//求方差
            dVar+=(x[i]-dAve)*(x[i]-dAve);
        }
        return (int) (dVar/m);
    }

}
